package io.renren.common.utils;

import java.io.*;
import java.net.URL;
import java.util.*;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import static io.renren.common.utils.DateUtils.DATE_PATTERN;
import static io.renren.common.utils.DateUtils.DATE_TIME_PATTERN;

/**
 * 阿里云 OSS文件类
 *
 * @author YangRenyu
 */
@Component
public class OSSClientUtil {

      private static Log log = LogFactory.getLog(OSSClientUtil.class);
      // endpoint以杭州为例，其它region请按实际情况填写
      private static String ENDPOINT = "http://oss-cn-qingdao.aliyuncs.com";
      // accessKey
      private static String ACCESS_KEY_ID = "LTAI5tGA8ND4fwfQnAYtv6gz";
      private static String ACCESS_KEY_SECRET = "7KxEbxJ1y905zwM1EVWnKeDWCubQpp";
      //空间
      private static String BUCKET_NAME = "1908aoss";
      //文件存储目录 data/
      private static String FOLDER_VIDEO = "video/";

      private static String FORMAT =  DateUtils.format(new Date(),DATE_PATTERN);
      private static String FORMATS = DateUtils.format(new Date(),DATE_TIME_PATTERN);

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    public static OSSClient getOSSClient() {
        return new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        //return new OSSClient("oss-cn-beijing.aliyuncs.com", "LTAI5tLuEo5USuY2Ta9gyX5S","SiO5A1DQmq4GuCrZLmctHIsgaYnpnJ");
    }

    /**
     * 创建存储空间
     *
     * @param ossClient  OSS连接
     * @param bucketName 存储空间
     * @return
     */
    public static String createBucketName(OSSClient ossClient, String bucketName) {
        // 存储空间
        final String bucketNames = bucketName;
        if (!ossClient.doesBucketExist(bucketName)) {
            // 创建存储空间
            Bucket bucket = ossClient.createBucket(bucketName);
            log.info("创建存储空间成功");
            return bucket.getName();
        }
        return bucketNames;
    }

    /**
     * 删除存储空间buckName
     *
     * @param ossClient  oss对象
     * @param bucketName 存储空间
     */
    public static void deleteBucket(OSSClient ossClient, String bucketName) {
        ossClient.deleteBucket(bucketName);
        log.info("删除" + bucketName + "Bucket成功");
    }

    /**
     * 创建模拟文件夹
     *
     *
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名如"qj_nanjing/"
     * @return 文件夹名
     */
    public static String createFolder(String bucketName, String folder) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        // 文件夹名
        final String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            log.info("创建文件夹成功");
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir = object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 根据key删除OSS服务器上的文件
     *
     *
     * @param bucketName 存储空间
     * @param key        Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
     */
    public static void deleteFile(String bucketName, String key) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        ossClient.deleteObject(bucketName, key);
        log.info("删除" + bucketName + "下的文件" + key + "成功");
    }

    /**
     * 根据存储空间获取OSS服务器上的文件
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     */
    public static List<OSSObjectSummary> getFiles(OSSClient ossClient, String bucketName) {
        // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
        ObjectListing objectListing = ossClient.listObjects(bucketName);
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
        // objectListing.getObjectSummaries获取所有文件的描述信息。
        log.info("根据存储空间获取OSS服务器上的文件" + bucketName + "下的文件成功");
        return sums;
    }



    /**
     * 获取包含指定前缀的文件。
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     * @param keyPrefix  指定前缀，例如exampledir/object。
     */
    public static List<OSSObjectSummary> getFilesByPrefix(OSSClient ossClient, String bucketName, String keyPrefix) {
        // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
        // 指定前缀，例如exampledir/object。
        // 列举包含指定前缀的文件。默认列举100个文件。
        ObjectListing objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).withPrefix(keyPrefix));
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
        log.info("获取" + bucketName + "下的" + keyPrefix + "文件成功");
        return sums;
    }

    /**
     * 获取包含指定前缀的文件。
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     * @param key        指定文件路径，不加bucketName，例如exampledir/object。
     */
    public static ObjectMetadata getFileByKey(OSSClient ossClient, String bucketName, String key) {
        // 获取Object，返回结果为OSSObject对象
        OSSObject object = ossClient.getObject(bucketName, key);

        // 获取ObjectMeta
        ObjectMetadata meta = object.getObjectMetadata();
        log.info("获取" + bucketName + "下的" + key + "+文件成功");
        return meta;
    }

    /**
     * 上传图片至OSS 文件流
     *
     * @param file       上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param path    模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     */
    public static String[] uploadObject2OSS(File file, String path) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        String resultStr = null;
        String[] fo = new String[]{"", ""};
        try {
            // 以输入流的形式上传文件
            String folder = "";
            folder = path + "/" + FORMAT + "/";
            InputStream is = new FileInputStream(file);
            // 文件名
            String timefile = FORMATS;
            String fileName = file.getName();
            String uuid = UUID.randomUUID().toString().replace("-", "");
            fileName = uuid + fileName.substring(fileName.lastIndexOf("."));
            log.info("上传到路径" + folder + fileName);
            // 文件大小
            Long fileSize = file.length();
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称
            // inline ：将文件内容直接显示在页面
            // attachment：弹出对话框让用户下载
            // filename=cccc 就是下载下来的文件名filename/filesize=" + fileName + "/" + fileSize + "Byte.
            metadata.setContentDisposition("inline;filename=" + fileName);
            // 指定上传文件操作时是否覆盖同名Object。
            // 不指定x-oss-forbid-overwrite时，默认覆盖同名Object。
            // 指定x-oss-forbid-overwrite为false时，表示允许覆盖同名Object。
            // 指定x-oss-forbid-overwrite为true时，表示禁止覆盖同名Object，如果同名Object已存在，程序将报错。
            metadata.setHeader("x-oss-forbid-overwrite", "true");
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(BUCKET_NAME, folder + fileName, is, metadata);
            // 解析结果
            resultStr = putResult.getETag();
            fo[1] = folder + fileName;
            fo[0] = resultStr;
            ossClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }
        return fo;
    }

    /**
     * 上传路径返回地址，图片视频都可以
     *
     * @param ossClient  oss连接
     * @param file       上传文件（文件全路径如：D:\\image\\cake.jpg）
     * @param bucketName 存储空间
     * @param path     模拟文件夹名 如"qj_nanjing/"
     * @return String 返回的唯一MD5数字签名
     * @return String 上传路径
     */
    public static String[] uploadObjectOSS(OSSClient ossClient, MultipartFile file, String bucketName, String path) {
        String resultStr = null;
        String[] fo = new String[]{"", ""};
        try {
            // 以输入流的形式上传文件
            String folder = "";
            folder = path + "/" + FORMAT + "/";
            // InputStream is = new FileInputStream(file);
            // 文件名
            //String timefile = FORMATS;
            String fileName = file.getOriginalFilename();
            String uuid = UUID.randomUUID().toString().replace("-", "");
            fileName = uuid + fileName.substring(fileName.lastIndexOf("."));
            log.info("上传到路径" + folder + fileName);
            // 文件大小
            long fileSize = file.getSize();
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
//            // 上传的文件的长度
//            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称
            // inline ：将文件内容直接显示在页面
            // attachment：弹出对话框让用户下载
            // filename=cccc 就是下载下来的文件名filename/filesize=" + fileName + "/" + fileSize + "Byte.
            metadata.setContentDisposition("inline;filename=" + fileName);
            // 指定上传文件操作时是否覆盖同名Object。
            // 不指定x-oss-forbid-overwrite时，默认覆盖同名Object。
            // 指定x-oss-forbid-overwrite为false时，表示允许覆盖同名Object。
            // 指定x-oss-forbid-overwrite为true时，表示禁止覆盖同名Object，如果同名Object已存在，程序将报错。
            metadata.setHeader("x-oss-forbid-overwrite", "true");
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, new ByteArrayInputStream(file.getBytes()), metadata);
            // 解析结果
            //String url = "http://" + bucketName + "." + endpoint + "/" + objectName;
            resultStr = putResult.getETag();
            fo[0] = resultStr;
            fo[1] = folder + fileName;

            ossClient.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        }
        return fo;
    }

    //上传视频
    public static String uploadByteVideoOSS(OSSClient ossClient, byte[] b, String bucketName, String user_id) {

        // byte[] content = "Hello OSS".getBytes();

        // 以输入流的形式上传文件
        String folder = "";
        folder = FOLDER_VIDEO + user_id + "/" + FORMAT + "/";
        // 文件名
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String timefile = uuid;// 文件名
        String fileName = ".MP4";// 后缀扩展名
        fileName = timefile + fileName;
        log.info("上传到路径" + folder + fileName);

        Long fileSize = (long) b.length;

        // 创建上传Object的Metadata
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(fileSize);
        // 指定该Object被下载时的网页的缓存行为
        metadata.setCacheControl("no-cache");
        // 指定该Object下设置Header
        metadata.setHeader("Pragma", "no-cache");
        // 指定该Object被下载时的内容编码格式
        metadata.setContentEncoding("utf-8");
        // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
        // 如果没有扩展名则填默认值application/octet-stream
        metadata.setContentType(getContentType(fileName));
        // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
        metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
        // 指定上传文件操作时是否覆盖同名Object。
        // 不指定x-oss-forbid-overwrite时，默认覆盖同名Object。
        // 指定x-oss-forbid-overwrite为false时，表示允许覆盖同名Object。
        // 指定x-oss-forbid-overwrite为true时，表示禁止覆盖同名Object，如果同名Object已存在，程序将报错。
        metadata.setHeader("x-oss-forbid-overwrite", "true");

        PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, new ByteArrayInputStream(b),
                metadata);
        ossClient.shutdown();
        String filepath = folder + fileName;
        return filepath;
    }

    //上传图片
    public static String uploadByteOSS(OSSClient ossClient, byte[] b, String bucketName, String path) {

        // byte[] content = "Hello OSS".getBytes();

        // 以输入流的形式上传文件
        String folder = "";
        folder = path + "/" + FORMAT + "/";
        // 文件名
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String timefile = uuid;// 文件名
        String fileName = ".jpg";// 后缀扩展名
        fileName = timefile + fileName;
        log.info("上传到路径" + folder + fileName);

        Long fileSize = (long) b.length;
//        String timefile = FORMATS;
//        file = timefile + file.substring(file.lastIndexOf("."));
        // 创建上传Object的Metadata
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(fileSize);
        // 指定该Object被下载时的网页的缓存行为
        metadata.setCacheControl("no-cache");
        // 指定该Object下设置Header
        metadata.setHeader("Pragma", "no-cache");
        // 指定该Object被下载时的内容编码格式
        metadata.setContentEncoding("utf-8");
        // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
        // 如果没有扩展名则填默认值application/octet-stream
        metadata.setContentType(getContentType(fileName));
        // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
        metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");

        PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, new ByteArrayInputStream(b),
                metadata);
        ossClient.shutdown();
        String filepath = folder + fileName;
        return filepath;
    }


    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static final String getContentType(String fileName) {
        // 文件的后缀名
        //String fileName = fileName.substring(fileName.lastIndexOf("."));
        if (fileName.equalsIgnoreCase(".bmp")) {
            return "application/x-bmp";
        }
        if (fileName.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (fileName.equalsIgnoreCase(".jpeg") ||
                fileName.equalsIgnoreCase(".jpg") ||
                fileName.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (fileName.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (fileName.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (fileName.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (fileName.equalsIgnoreCase(".pptx") ||
                fileName.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (fileName.equalsIgnoreCase(".docx") ||
                fileName.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (fileName.equalsIgnoreCase(".xla") ||
                fileName.equalsIgnoreCase(".xlc") ||
                fileName.equalsIgnoreCase(".xlm") ||
                fileName.equalsIgnoreCase(".xls") ||
                fileName.equalsIgnoreCase(".xlt") ||
                fileName.equalsIgnoreCase(".xlw")) {
            return "application/vnd.ms-excel";
        }
        if (fileName.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (fileName.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (fileName.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (fileName.equalsIgnoreCase(".tar")) {
            return "application/x-tar";
        }
        if (fileName.equalsIgnoreCase(".avi")) {
            return "video/avi";
        }
        if (fileName.equalsIgnoreCase(".mp4")) {
            return "video/mp4";
        }
        if (fileName.equalsIgnoreCase(".mp3")) {
            return "audio/mp3";
        }
        if (fileName.equalsIgnoreCase(".mp2")) {
            return "audio/mp2";
        }
        // 默认返回类型
        return "application/octet-stream";
    }

    /**
     * 获得url链接
     *
     * @param
     * @param bucketName
     * @param fileName
     * @return
     */
    public static String getUrl(String bucketName, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 10);
        // 生成URL
        URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);

        if (url != null) {
            return url.toString().replace("http","https");
        }
        return "获网址路径出错";
    }

    public static void MergeFile(List<InputStream> streamList,String mergePath){

        Enumeration<InputStream> enumeration = Collections.enumeration(streamList);
        SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        String fileExtension = mergePath.substring(mergePath.lastIndexOf("."));
        ObjectMetadata metadata = new ObjectMetadata();
        // 指定该Object被下载时的网页的缓存行为
        metadata.setCacheControl("no-cache");
        // 指定该Object下设置Header
        metadata.setHeader("Pragma", "no-cache");
        // 指定该Object被下载时的内容编码格式
        metadata.setContentEncoding("utf-8");
        // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
        // 如果没有扩展名则填默认值application/octet-stream
        metadata.setContentType(getContentType(fileExtension));
        PutObjectResult putObjectResult = ossClient.putObject(BUCKET_NAME, mergePath, sequenceInputStream,metadata);

    }

    /**
     * 上传图片至OSS 文件流
     *
     *
     *
     * @return String 返回的唯一MD5数字签名
     */
    public static HashMap<String, Object> uploadObject2OSS(String fileMd5, String videoPath, String suffix) throws Exception{
        HashMap<String, Object> resultMap = new HashMap<>();
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        String[] resultArr = new String[2];
        System.out.println(videoPath);
        try {
            //重新命名文件，文件夹要是改动，app记录删除的地方一并改动
            String fileName =UUID.randomUUID().toString() + suffix;
            String objectName = FOLDER_VIDEO+fileMd5.substring(0,1) + "/" + fileMd5.substring(1,2) + "/" + fileMd5 + "/" + fileName;
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(BUCKET_NAME, objectName);
            // 如果需要在初始化分片时设置请求头，请参考以下示例代码。
             ObjectMetadata metadata = new ObjectMetadata();
             metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // 指定该Object的网页缓存行为。
             metadata.setCacheControl("no-cache");
             metadata.setContentType(getContentType(suffix));
            // 指定该Object被下载时的名称。
            // metadata.setContentDisposition("attachment;filename=oss_MultipartUpload.txt");
            // 指定该Object的内容编码格式。
            // metadata.setContentEncoding(OSSConstants.DEFAULT_CHARSET_NAME);
            // 指定初始化分片上传时是否覆盖同名Object。此处设置为true，表示禁止覆盖同名Object。
            // metadata.setHeader("x-oss-forbid-overwrite", "true");
            // 指定上传该Object的每个part时使用的服务器端加密方式。
            // metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
            // 指定Object的加密算法。如果未指定此选项，表明Object使用AES256加密算法。
            // metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_DATA_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
            // 指定KMS托管的用户主密钥。
            // metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****");
            // 指定Object的存储类型。
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
            // 指定Object的对象标签，可同时设置多个标签。
            // metadata.setHeader(OSSHeaders.OSS_TAGGING, "a:1");
             request.setObjectMetadata(metadata);

            // 初始化分片。
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            // 返回uploadId，它是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作，例如取消分片上传、查询分片上传等。
            String uploadId = upresult.getUploadId();
            resultMap.put("uploadId",uploadId);
            resultMap.put("uploadId:"+uploadId, objectName);

            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
            List<PartETag> partETags =  new ArrayList<PartETag>();
            // 每个分片的大小，用于计算文件有多少个分片。单位为字节。
            final long partSize = 1 * 1024 * 1024L;   //1 MB。

            // 填写本地文件的完整路径。如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
            File file = new File(videoPath);
            long fileLength = file.length();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }
            // 遍历分片上传。
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
                // 跳过已经上传的分片。
                InputStream instream = new FileInputStream(file);
                instream.skip(startPos);
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(BUCKET_NAME);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(instream);
                // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
                uploadPartRequest.setPartSize(curPartSize);
                // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出此范围，OSS将返回InvalidArgument错误码。
                uploadPartRequest.setPartNumber(i + 1);
                // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                // 每次上传分片之后，OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
                partETags.add(uploadPartResult.getPartETag());
            }

            // 创建CompleteMultipartUploadRequest对象。
            // 在执行完成分片上传操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(BUCKET_NAME, objectName, uploadId, partETags);

            // 完成分片上传。
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            resultArr[0] = completeMultipartUploadResult.getETag();
            resultArr[1] = objectName;
            resultMap.put("partETags:"+uploadId, partETags);
            resultMap.put("resultArr",resultArr);
            System.out.println(completeMultipartUploadResult.getETag());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return resultMap;
    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) {
        try {
            File toFile;
            if (file != null && file.getSize() > 0) {
                InputStream ins = null;
                ins = file.getInputStream();
                toFile = new File(file.getOriginalFilename());
                inputStreamToFile(ins, toFile);
                ins.close();
                return toFile;
            }
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取流文件
     *
     * @param ins
     * @param file
     */
    public static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Boolean doesObjectExist(String remoteFileName) {
        // endpoint以杭州为例，其它region请按实际情况填写
        // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录
        // 创建OSSClient实例
        OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        Boolean result=ossClient.doesObjectExist( BUCKET_NAME,remoteFileName);
        // 关闭OSSClient。
        ossClient.shutdown();
        return result;
    }

//    public String urlpath(String user_id, String files) {
//        OSSClient ossClient = AliyunOSSClientUtil.getOSSClient();
//        String[] file = files.split(",");
//        String url = "";
//        for (String filename : file) {
//            // System.out.println("filename:"+filename);
//            File filess = new File(filename);
//            String[] s = AliyunOSSClientUtil.uploadObject2OSS(ossClient, filess, BUCKET_NAME, user_id);
//            log.info("上传后的文件MD5数字唯一签名:" + s[0]);
//            log.info("文件路径:" + s[1]);
//            url = AliyunOSSClientUtil.getUrl(ossClient, BUCKET_NAME, s[1]);
//            log.info("访问网址路径:" + url);
//        }
//        // 上传后的文件MD5数字唯一签名:40F4131427068E08451D37F02021473A
//        return url;
//    }

}